﻿using System.Collections.Generic;


using Mogre;
using System;
using MultiAgents.Modules;
using MultiAgents.States;


namespace MultiAgents
{
    class View
    {
        public static OgreManager mEngine;
        private static StateManager mStateMgr;
        private List<SceneNode> mOgreHead;
        private List<SceneNode> mRobot;
        private bool _isRunning;
        private Vector3 _CamTrans;
        private Vector3 _CamRot;
        private float _move;

        public void CreateView(List<Ogre> o, List<Robot> r)
        {
            _isRunning = true;
            _move = 25;
            _CamTrans = new Vector3();
            _CamRot = new Vector3();
            mOgreHead = new List<SceneNode>();
            mRobot = new List<SceneNode>();

            // create Ogre manager
            mEngine = new OgreManager();

            // create state manager
            mStateMgr = new StateManager(mEngine);

            // set a dark ambient light
            //mEngine.SceneMgr.AmbientLight = new ColourValue(0.1f, 0.1f, 0.1f);

          
            /*Fail*/
          // mEngine.SceneMgr.SetSkyBox(true, "Examples/SpaceSkyBox");
           //mEngine.SceneMgr.SetSkyDome(true, "Examples/CloudySky", 5, 8); //commenté pour debuger
            

            // try to initialize Ogre and the state manager
            if (mEngine.Startup() && mStateMgr.Startup(typeof(StateGame)))
            {
                // create ogre graphic representations
                for (int i = 0; i < r.Count; ++i)
                {
                    AddGraphRepresRobot(r, i);
                }

                for (int i = 0; i < o.Count; ++i)
                {
                    AddGraphRepresOgre(o, i);
                }
            }
        }

        private void AddGraphRepresRobot(List<Robot> r, int i)
        {
            
            SceneNode sn = mEngine.CreateSimpleObject("Robot" + i, "robot.mesh");
            sn.Position = r[i].getPosition();
            mEngine.AddObjectToScene(sn);
            mRobot.Add(sn);
        }

        private void AddGraphRepresOgre(List<Ogre> o, int i)
        {
            SceneNode sn = mEngine.CreateSimpleObject("Ogre" + i, "ogrehead.mesh");
            sn.Position = o[i].getPosition();
            mEngine.AddObjectToScene(sn);
            mOgreHead.Add(sn);
        }

         public void UpdateView(List<Ogre> o, List<Robot> r)
        {
            // update the state manager, this will automatically update the active state
            mStateMgr.Update(0);
            if(mStateMgr.Input.IsKeyDown(MOIS.KeyCode.KC_LEFT)) {
                _CamTrans.x -= _move;
            }

            if (mStateMgr.Input.IsKeyDown(MOIS.KeyCode.KC_RIGHT))
            {
                _CamTrans.x += _move;
            }

            if (mStateMgr.Input.IsKeyDown(MOIS.KeyCode.KC_UP))
            {
                _CamTrans.y += _move;
            }

            if (mStateMgr.Input.IsKeyDown(MOIS.KeyCode.KC_DOWN))
            {
                _CamTrans.y -= _move;
            }

            if (mStateMgr.Input.IsKeyDown(MOIS.KeyCode.KC_PGUP))
            {
                _CamTrans.z -= _move;
            }

            if (mStateMgr.Input.IsKeyDown(MOIS.KeyCode.KC_PGDOWN))
            {
                _CamTrans.z += _move;
            }

            if (mStateMgr.Input.MouseMoveX != 0)
            {
                _CamRot.x = mStateMgr.Input.MouseMoveX;
            }

            if (mStateMgr.Input.MouseMoveY != 0)
            {
                _CamRot.y = mStateMgr.Input.MouseMoveY;
            }

            if (mStateMgr.Input.MouseMoveZ != 0)
            {
                _CamRot.z = mStateMgr.Input.MouseMoveZ;
            }


             /*Ajuster le nombre de representation graphique à celui de non graphiques: */
             /*Ajouter des représentations graphiques*/
            for (int i = mOgreHead.Count; i < o.Count; ++i)
            {
                AddGraphRepresOgre(o,i);
            }
             /*Supprimer ceux qui existent en trop*/
            for (int i = mOgreHead.Count ; i > o.Count; --i)
            {
                mEngine.RemoveObjectFromScene(mOgreHead[i-1]);
                mEngine.DestroyObject(mOgreHead[i-1]);
                Console.WriteLine("Destruction graphique de l'ogre "+(i-1));
            }
            mOgreHead.RemoveRange(o.Count, (mOgreHead.Count-o.Count));

            // Mettre à jour les ogres qui ont déjà une représentation graphique
            for (int i = 0; i < mOgreHead.Count; ++i)
            {
                mOgreHead[i].Position = o[i].getPosition();
            }

            // Mettre à jour les robots qui ont déjà une représentation graphique
            for (int i = 0; i < mRobot.Count; ++i)
            {
                mRobot[i].Position = r[i].getPosition();
            }


             /*Mise à l'echelle des robots en fonction de la valeur absolue de leur puissance*/
             /*float s;
             for (int i = 0; i < mRobot.Count; ++i)
             {
                 s = System.Math.Abs(r[0].getPower()) + 1;//car désormais correspondance mrobot et r
                 s = s / 2;
                 mRobot[i].SetScale(s, s, s);
                 if(r[i].getPower()>0)
                     mRobot[i].SetOrientation(1, 1, 1, 1);
                 else
                     mRobot[i].SetOrientation(1, -1, 1, 1);
             }*/
             /*Mise à l'echelle des ogres en fonction de la valeur absolue de leur pv*/
            /* for (int i = 0; i < mOgreHead.Count; ++i)
             {
                 s = System.Math.Abs(o[i].getPv()) + 1;
                 s = s / 10;
                 mOgreHead[i].SetScale(s, s, s);
             }*/


            mEngine.Update(_CamTrans, _CamRot);

            _CamTrans = new Vector3();
            _CamRot = new Vector3();

            if (mStateMgr.ShuttingDown)
            {
                ShutDownView();
                _isRunning = false;
            }
        }

        private Degree[] MyComputeAngle(Vector3 direction, Vector3 oldDirection)
        {
            /*Calcul des vecteurs normalisés dans plan XY pour la rotation autour de Z*/
            Vector2 directionz = new Vector2(direction.x, direction.y);
            directionz.Normalise();
            Vector2 olddirectionz = new Vector2(oldDirection.x, oldDirection.y);
            olddirectionz.Normalise();

            /*Calcul des vecteurs normalisés dans plan YZ pour la rotation autour de X*/
            Vector2 directionx = new Vector2(direction.y, direction.z);
            directionx.Normalise();
            Vector2 olddirectionx = new Vector2(oldDirection.y, oldDirection.z);
            olddirectionx.Normalise();

            /*Calcul de l'angle de rotation autour de Z:*/
            double angle_z = System.Math.Acos(myDotProduct(directionz, olddirectionz));
            Degree angle_z_degree = new Degree((float)angle_z);

            /*Calcul de l'angle de rotation autour de X:*/
            double angle_x = System.Math.Acos(myDotProduct(directionx, olddirectionx));
            Degree angle_x_degree = new Degree((float)angle_x);

            Degree[] angles = new Degree[2];
            angles[0] = angle_z_degree;
            angles[1] = angle_x_degree;
            
            return angles;
        }

        

         private double myDotProduct(Vector2 A, Vector2 B)
         {
             return (A.x * B.x + A.y * B.y);
         }

        public void RemoveScene()
        {

            // check if ogre head exists
            if (mOgreHead != null)
            {
                // remove ogre head from scene and destroy it

                for (int i = 0; i < mOgreHead.Count; i++)
                {
                    mEngine.RemoveObjectFromScene(mOgreHead[i]);
                    mEngine.DestroyObject(mOgreHead[i]);
                    mOgreHead[i] = null;
                }
                mOgreHead = null;
            }

            if (mRobot != null)
            {
                // remove ogre head from scene and destroy it

                for (int i = 0; i < mRobot.Count; i++)
                {
                    mEngine.RemoveObjectFromScene(mRobot[i]);
                    mEngine.DestroyObject(mRobot[i]);
                    mRobot[i] = null;
                }
                mRobot = null;
            }
        }

        public void ShutDownView()
        {
            // Le jour opù on l'appelle, virer mStateManager

            // check if state manager is in shutting down state
            if (mStateMgr.ShuttingDown)
            {
                // destroy the window to shut down the application
                mEngine.Window.Destroy();
            }

            RemoveScene();

            // shut down state manager
            mStateMgr.Shutdown();

            // shutdown Ogre
            mEngine.Shutdown();
        }

        public bool isRunning()
        {
            return _isRunning;
        }

       
    }
}
